module Oos4ruby
module Bean #:nodoc:
  def self.append_features(base)
    super
    base.extend(ClassMethods)
  end
  
  module ClassMethods #:nodoc:
    def define_el_reader(opts = {})
      if !opts.empty?
        opts.each_pair { |key, value|
          value.each { |field_name|
            define_method(field_name) do            
              name = field_name.to_s.gsub(/_/, '')
              begin
                child = @xml.child(name, key) if @xml.instance_of?Oos4ruby::Entry
                child = REXML::XPath.first(@xml, name, key) if @xml.instance_of? REXML::Element
                return child.text if child
              rescue => e                
                puts e.backtrace.join("\n")
              end
            end
          }
        }
      end
    end
    
    def set_variable(options = {})
      if options.empty?
        options.each_pair { |key, value|
          class_variable_set("@@#{key.to_s}".to_sym, value) 
        }
      end
    end
      
    def define_attr_reader(opts = {})
      if !opts.empty?
        opts.each_pair { |namespace, value|
          if value.is_a?Array
            value.each { |field|            
                define_method(field) do
                  name = field.to_s.gsub(/_/, '')
                  begin
                    attr = @xml.attribute(name, namespace) if @xml.instance_of? REXML::Element
                    return attr.value
                  rescue
                    #ATTRIBUTE NOT FOUND
                  end                  
                end              
            }
          elsif value.is_a?Hash
            value.each_pair { |el, attr|
              define_method("#{el}_#{attr}") do
                el = el.to_s.gsub(/_/, '')
                
                prefix = 'atom'
                XmlNamespaces.each_pair { |name_key, name_value|
                  prefix = name_key if name_value.to_s == namespace.to_s
                }
                
                elem = @xml.child(el, namespace) if @xml.instance_of?Oos4ruby::Entry
                elem = REXML::XPath.first(@xml, "./#{prefix}:#{el}", namespace) if @xml.instance_of?REXML::Element
                  
                if (attr.is_a?Symbol)
                  attr = attr.to_s.gsub(/_/, '')
                  begin
                    attr_value = elem.attribute(attr, namespace)
                    return attr_value.value
                  rescue
                    #ATTRIBUTE NOT FOUND
                  end
                elsif attr.is_a?Hash
                  attr.each_pair { |attr_name, attr_namespace|
                  attr_name = attr_name.to_s.gsub(/_/, '')
                  begin
                    attr_value = elem.attribute(attr_name, attr_namespace)
                    return attr_value.value
                  rescue
                    #ATTRIBUTE NOT FOUND
                  end
                  }
                end
              end
            }
          end
        }
      end
    end
  end
  
  class BeanClass
    def author
      @entry.child('author/name').text
    end
    
    def to_xml
      @xml.to_s
    end
    
    def to_s
      @xml.to_s
    end
    
    def contains?(elem, value)
      xpath = @xml.first(elem)
      return xpath && xpath.text == value
    end
    
    def update!
      edit_link = @xml.link('edit')

      getter = HTTPInvoker.new(edit_link, @auth)

      worked = getter.get
      if worked
        @xml = Entry.new( getter.body )
        load!

        putter = HTTPInvoker.new edit_link, @auth
        worked = putter.put AtomEntryContentType, @xml.to_s

        raise RuntimeError.new unless worked
      else
        raise RuntimeError.new unless worked
      end    
    end
    
    def delete!
      edit_link = @xml.link('edit')

      deleter = HTTPInvoker.new(edit_link, @auth)

      worked = deleter.delete

      raise RuntimeError.new unless worked    
    end
    
    protected
    def add_category(term, scheme)
      self.add_category(@xml, term, scheme)
    end
    
    def update_category(new_term, new_scheme, old_term = nil, old_scheme = nil)
      remove_category old_term, old_scheme
      add_category new_term, new_scheme
    end
    
    def remove_category(term = nil, scheme = nil)
      self.remove_category(@xml, term, scheme)
    end
    
    def self.make_id
      id = ''
      5.times { id += rand(1000000).to_s }
      "Oos4ruby:11870.com,2007:#{id}"
    end

    def self.add_element(base, new_el, text, attrs = {})
      elements = new_el.to_s.split("/")
      last = elements[elements.size - 1]
      elements.pop
      root_el = base
      elements.each do |path|
        root_el = base.add_element(path)      
      end
      el = root_el.add_element last.to_s, attrs
      el.text = text
    end

    def self.add_category(xml, term, scheme)
      xml.add_category(term.to_s, scheme)
    end

    def self.remove_category(xml, term = nil, scheme = nil)
      if xml.is_a?Entry
      hash = {}
      hash[:term] = term if term
      hash[:scheme] = scheme if scheme      
      cat = xml.category( hash )
      xml.delete_category( cat ) if cat
      elsif xml.is_a?REXML::Element
        xml.delete_element c
      end
    end

    def self.create_entry
      entry = REXML::Element.new('entry')
      entry.add_namespace AtomNamespace
      XmlNamespaces.each_pair { |prefix, namespace|
        unless prefix == 'atom' || prefix == 'gml'
          entry.add_namespace prefix, namespace
        end
      }
      entry
    end
    
  end
end
end

